/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ichatGUI;

import MessageIO.ChatUsername;
import MessageIO.MessageListener;
import MessageIO.MessageManager;
import MessageIO.SocketConstants;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.BevelBorder;


/**
 * ClientGUI is directly taken from the DeitelMessenger class in Deitel and
 * Deitel's Java: How To Program.  The class is the client side GUI for
 * using the instant messenger program
 * @author Mark
 */
public class ClientGUI extends JFrame
    {
    private JMenu serverMenu;// for connecting/disconnecting server
    private JTextArea messageArea;//displays messages
    private JTextArea inputArea;//inputs messages
    private JTextArea userNameListArea;//shows the users in the room
    private JButton connectButton;// button for connecting
    private JMenuItem connectMenuItem;//menu item for connecting
    private JButton disconnectButton;//button for disconnecting
    private JMenuItem disconnectMenuItem;//menu item for disconnecting
    private JButton sendButton;//sends messages
    private JLabel statusBar;//label for connection status
    private ChatUsername userName;//Username for the Client
    private ArrayList<String> users;
    private MessageManager messageManager;//communicates with server
    private MessageListener messageListener;// receives incoming messages
    private Blinker blinker;//The class used to blink the window
    private boolean windowDeiconified;//used to see if the window is open or not
    private boolean newMessageReceived;// used for flashing window when new
                                        //message is received

    /**
     * Creates an instance of ClientGUI
     * @param manager used to manage the messeges sent and received
     */
    public ClientGUI(MessageManager manager)
        {
        super("iMarkChat");
        messageManager = manager;//set the MessageManager
        userName = null;//sets name to null at the beginning
        users = null;//sets users to null
        newMessageReceived = false;
        windowDeiconified = true;
        blinker = new Blinker(this);

        Toolkit kit = Toolkit.getDefaultToolkit();//Gets the Toolkit
        this.setIconImage(kit.createImage("messenger.png"));
        //uses the Toolkit to make the image

        //create MyMessageListener for receiving messages
        messageListener = new MyMessageListener();


        serverMenu = new JMenu("Server");//create Server JMenu
        serverMenu.setMnemonic('S');//mnemonic for server menu
        JMenuBar menuBar = new JMenuBar();//create JMenuBar
        menuBar.add(serverMenu);// add server menu to menu bar
        setJMenuBar(menuBar);//add JMenuBar to application

        //create ImageIcon for connect buttons
        Icon connectIcon = new ImageIcon("connect.png");

        //create connectButton and connectMenuItem
        connectButton = new JButton("Connect", connectIcon);
        connectMenuItem = new JMenuItem("Connect",connectIcon);
        connectMenuItem.setMnemonic('C');

        //create ConnectListener for connectbuttons
        ActionListener connectListener = new ConnectListener();
        connectButton.addActionListener(connectListener);
        connectMenuItem.addActionListener(connectListener);

        //create ImageIcon for disconnect buttons
        Icon disconnectIcon = new ImageIcon("disconnect.png");

        //create disconnectButton and disconnectMenuItem
        disconnectButton = new JButton("Disconnect", disconnectIcon);
        disconnectMenuItem = new JMenuItem("Disconnect", disconnectIcon);
        disconnectMenuItem.setMnemonic('D');

        //disable disconnect button and menu item
        disconnectButton.setEnabled(false);
        disconnectMenuItem.setEnabled(false);

        //create DisconnectListener for disconnect buttons
        ActionListener disconnectListener = new DisconnectListener();
        disconnectButton.addActionListener(disconnectListener);
        disconnectMenuItem.addActionListener(disconnectListener);

        //add connect and disconnect JMenuItems to fileMenu
        serverMenu.add(connectMenuItem);
        serverMenu.add(disconnectMenuItem);

        //add connect and disconnect JButtons to buttonPanel
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(connectButton);
        buttonPanel.add(disconnectButton);
        
        messageArea = new JTextArea();//displays messages
        messageArea.setEditable(false);//displays editing
        messageArea.setWrapStyleWord(true);//set srap style to word
        messageArea.setLineWrap(true);//enable line wrapping

        userNameListArea = new JTextArea();//displays users in room
        userNameListArea.setEditable(false);//displays editing
        userNameListArea.setWrapStyleWord(true);//set srap style to word
        userNameListArea.setLineWrap(true);//enable line wrapping
        
        //put message Area in JScrollPane to enable scrolling
        JPanel messagePanel = new JPanel();
        messagePanel.setLayout(new BorderLayout(10, 10));
        messagePanel.add(new JScrollPane(messageArea), BorderLayout.CENTER);
        messagePanel.add(new JScrollPane(userNameListArea), BorderLayout.WEST);

        inputArea = new JTextArea(4,20);//for entering new messages
        inputArea.addKeyListener(
                new KeyAdapter() {

            /**
             * Makes it so it sends message when enter is pressed, it sends
             * the message
             */
            @Override
            public void keyTyped(KeyEvent e)
                {
                if (e.getKeyChar() == 10)
                    {
                    messageManager.sendMessage(userName.getUserName(),
                            inputArea.getText());
                    //send Message
                    System.out.println(inputArea.getText());
                    inputArea.setText("");//clears input
                    }
                }
        });

        inputArea.setWrapStyleWord(true);//set wrap style to word
        inputArea.setLineWrap(true);//enable line wrapping
        inputArea.setEditable(false);//disable editing

        //create Icon for sendButton
        Image img = Toolkit.getDefaultToolkit().createImage("send.png");
        Icon sendIcon = new ImageIcon(img);

        sendButton = new JButton("Send", sendIcon);
        sendButton.setEnabled(false);
        sendButton.addActionListener(
                new ActionListener()
                    {
                    public void actionPerformed(ActionEvent e)
                        {
                        messageManager.sendMessage(userName.getUserName(),
                                inputArea.getText());
                        //send Message
                        System.out.println(inputArea.getText());
                        inputArea.setText("");//clears input
                        }//end method
                    });//end anonymous inner class and end call to addAction
        JScrollPane pane = new JScrollPane(inputArea);
        
        Box box = new Box(BoxLayout.X_AXIS);//creates new box for layout
        box.add(pane);//add input area to box
        box.add(sendButton);//add send button to box
        messagePanel.add(box, BorderLayout.SOUTH);//add box to panel

        //create JLabel for statusBar with recessed border
        statusBar = new JLabel("Not Connected");
        statusBar.setBorder(new BevelBorder(BevelBorder.LOWERED));

        add(buttonPanel, BorderLayout.NORTH);//button panel
        add(messagePanel,BorderLayout.CENTER);//add message panel
        add(statusBar, BorderLayout.SOUTH);//add status bar

        //add WindowListener to disconnect when user quits
        addWindowListener(
                new WindowAdapter()
                    {
                    @Override
                    public void windowClosing(WindowEvent event)
                        {
                        //disconnect rom server and exit application
                        messageManager.disconnect(messageListener, userName);
                        System.exit(0);
                        }

                    @Override
                    public void windowActivated(WindowEvent e)
                        {
                        windowDeiconified = true;
                        }

                    @Override
                    public void windowDeactivated(WindowEvent e)
                        {
                        windowDeiconified = false;
                        }

                    @Override
                    public void windowDeiconified(WindowEvent e)
                        {
                        windowDeiconified = true;
                        }

                    @Override
                    public void windowIconified(WindowEvent e)
                        {
                        windowDeiconified = false;
                        }

                    }
            );
        }

    /**
     * Receives the String from the Server with the usernames and then makes
     * and arraylist and adds the names to that list
     * @param lols the String which to make a list into
     */
    private void stringToUserNames(String lols)
        {
        lols = lols.substring(1, lols.length() - 1);//gets rid of brackets
        System.out.println(lols);//Print the current state
        if (lols.length() == 0)//if its not a blank String
            return;
        /**
         * Beg is the index of the first letter, end is the index of the last
         * letter.  After adding the username the beg them looks for the
         * first letter after the next comma and then ends follows
         */
        for (int beg = 0, end = lols.indexOf("@", beg); beg != -1;
            beg = lols.indexOf(",", end), end =lols.indexOf("@", beg))
            {
            String addingName = lols.substring(beg, end);
                System.out.println(addingName);
            if (addingName.indexOf(",") == 0)
                addingName = addingName.substring(2);
                System.out.println(addingName);
            users.add(addingName);
            }
        }

    /**
     * Refreshes the ArrayList of users
     */
    private void refreshUsers()
        {
        if (users == null)
            return;
        String text = "Chat Room Users:\n";
        for (String user: users)
            text += user + "\n";
        userNameListArea.setText(text);
        }

    /**
     * Determines if the username is invalid
     * @param username the username to be judged
     * @return true if invalid, false if valid
     */
    private boolean invalidUsername(String username)
        {
        return (username == null || username.equals("") || username.equals("Server")
                ||username.indexOf("@") != -1 || username.indexOf("$") != -1 ||
                username.indexOf(",") != -1 || username.indexOf(":") != -1 ||
                username.indexOf(">") != -1);
        }

    /**
     * A class which uses actionPerformed to enable/disable buttons when
     * the connect button is pressed
     */
    private class ConnectListener implements ActionListener
        {
        public void actionPerformed(ActionEvent e)
            {
            //connect to server and route messages to messageListener
            messageManager.connect(messageListener);
            users = new ArrayList<String>();//initiates the users
            //prompt for userName
            if (userName == null)
                {
                String promptName = null;
                while (invalidUsername(promptName))//Asks the user to input name
                    promptName = JOptionPane.showInputDialog(ClientGUI.this,
                            "Enter user name:");
                try 
                    {//Make a new ChatUsername with the username and getting ip
                    userName = new ChatUsername(promptName, InetAddress.
                            getLocalHost().toString());
                    }
                catch (UnknownHostException ex)
                    {
                    ex.printStackTrace();
                    }
                }
            messageManager.sendMessage("", userName + SocketConstants.
                        USERNAME_INDICATOR);//Tells the server there is a new
            //user

            messageArea.setText("");//clear messageArea
            userNameListArea.setText("Chat Room Users:\n");
            connectButton.setEnabled(false);//disable connect
            connectMenuItem.setEnabled(false);//disable connect
            disconnectButton.setEnabled(true);//enable disconnect
            disconnectMenuItem.setEnabled(true);//enable disconnect
            sendButton.setEnabled(true);//enable send button
            inputArea.setEditable(true);//enable editing for input area
            inputArea.requestFocus();//setfocus to input area
            statusBar.setText("Connected: " + userName);//set text
            }//end method action performed
        }//end ConnectListener inner class

    /**
     * DisconnectListener listens for user requests to disconnect from
     * MessengerServer
     */
    private class DisconnectListener implements ActionListener
        {
        //disconnect from server and enable/disable GUI components
        public void actionPerformed(ActionEvent event)
            {
            //disconnect from server and stop routing messages
            messageManager.disconnect(messageListener, userName);
            sendButton.setEnabled(false);//disable send button
            disconnectButton.setEnabled(false);//disable disconnect
            disconnectMenuItem.setEnabled(false);//disable disconnect
            inputArea.setEditable(false);//disable editing
            connectButton.setEnabled(true);///enable connect
            statusBar.setText("Not Connected");//set status bar text
            users = null;//sets users to null
            }
        }//end DisconnectListener innner class

    /**
     * MyMessageListener listens for new messages from MessageManager
     * and displays messages in messageArea using Message Displayer
     */
    private class MyMessageListener implements MessageListener
        {
        //when received, display ne wmessages in messageArea
        public void messageReceived(String from, String message)
            {
            //Append message using MessageDisplayer
            if (!from.equals(""))//if it has a sender
                {
                /**
                 * If it is from a regular user the message is displayed,
                 * if its from the server, the message is displayed as well as
                 * acting on the entrance/departure of one of the chatroom
                 * users.  Adds/Removes from the ArrayList
                 */
                if (from.equals("Server"))
                    {
                    if (message.indexOf("entered") != -1)
                        users.add(message.substring(0, message.indexOf(
                                SocketConstants.SERVER_ROOM_ENTER) - 1));
                    else
                        {
                        if(users != null)
                            users.remove(message.substring(0, message.indexOf(
                                    SocketConstants.SERVER_ROOM_LEFT) - 1));
                        }
                    refreshUsers();
                    }
                new MessageDisplayer(from, message).run();
                }
            else//if it doesnt have a sender
                {
                if (message.indexOf(SocketConstants.TO_NEW_USER) != -1 &&
                        message.indexOf("@" + userName.getUserName() + "$$") != -1)
                    {//receives the users list if this user is a new user
                    String list = message.substring(2 + message.indexOf("$$"));
                    stringToUserNames(list);
                    refreshUsers();
                    }
                if (message.indexOf(SocketConstants.TERMINATE_USER) != -1)
                    {//is terminated by the server
                    String temp = message.substring(SocketConstants.
                            TERMINATE_USER.length() + 3);
                    if (temp.equals(userName.toString()))
                        {//disconnects if it is this user for name duplication
                        new DisconnectListener().actionPerformed(null);
                        JOptionPane.showMessageDialog(ClientGUI.this, "Disconnected for " +
                                "User Name duplication");
                        userName = null;
                        }
                    }

                }
            }
        }//end MyMessageListener inner class

    /**
     * Displays new message by appending message to JtextArea.  Should be
     * executed only in Event thread; modifies live Swing component
     */
    private class MessageDisplayer implements Runnable
        {
        private String fromUser;//user from which message came
        private String messageBody;//body of message

        /**
         * Creates a new instance of MessageDisplayer
         * @param from the userName from
         * @param body the message body
         */
        public MessageDisplayer(String from, String body)
            {
            super();
            fromUser = from;//store originating user
            messageBody = body;//store message body
            }

        //display new message in messageArea
        public void run()
            {
//            disconnectButton.getActionListeners()[0].actionPerformed(null);
            //append new message
            messageArea.append("\n" + fromUser + "("
                    + new Date().toString().substring(11,19) + ")"
                    +SocketConstants.MESSAGE_SEPERATOR + " " + messageBody);
            //automatically scrolls down
            messageArea.selectAll();
            int x = messageArea.getSelectionEnd();
            messageArea.select(x,x);
//            ExecutorService service = Executors.newCachedThreadPool();
            if (!windowDeiconified)
                toFront();
            }
        }//end MessageDisplayer innerclass

    private class Blinker implements Runnable
        {
        private JFrame frame;
        public Blinker(JFrame frame)
            {
            super();
            this.frame = frame;
            }

        public void run()
            {
            try
                {
                Window win = frame.getOwner();
                while (!windowDeiconified)
                    {
                    int sleepTime = 50;
                    frame.setVisible(false);
                    Thread.sleep(sleepTime);
                    frame.setVisible(true);
                    Thread.sleep(sleepTime);
                    }
                }
            catch (InterruptedException ie)
                {
                ie.printStackTrace();
                }
            }

        }

    }
